package com.ldq.imooc.basics.multiThread;

/**
 * @Author : 李道泉
 * @Description :
 * @Date : 2018/4/24 8:48
 * @Modified by :
 */
public class EnergySystem {

    //能量存贮,能量盒子
    private final double[] energyBoxes;

    //增加锁的对象
    private final Object lockObj = new Object();

    /**
     * @param n             能量盒子数量
     * @param initialEnergy 每个能量盒子初始能量值
     * @Author : 李道泉
     * @Description :
     * @Date 2018/4/24 8:54
     * @Modified by :
     */
    public EnergySystem(int n, double initialEnergy) {
        energyBoxes = new double[n];
        for (int i = 0; i < energyBoxes.length; i++) {
            energyBoxes[i] = initialEnergy;
        }
    }

    /**
     * @Author : 李道泉
     * @Description :  能量转移，一个盒子到另一个盒子
     * @Date 2018/4/24 8:57
     * @Modified by :
     */
    public void transfer(int from, int to, double amount) {

        //对此段代码互斥操作
        synchronized (lockObj) {

            //保证条件不满足时，任务都会被条件阻挡,以免继续竞争CPU资源
            //wait set
            while (energyBoxes[from] < amount) {
                try {
                    //条件不满足，将当前线程放入wait set
                    lockObj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName());
            energyBoxes[from] -= amount;
            System.out.printf("从%d转移%10.2f单位能量到%d", from, amount, to);
            energyBoxes[to] += amount;
            System.out.printf("能量总和：%10.2f%n", getTotalEnergies());

            //唤醒所有在lockObj对象上等待的线程
            lockObj.notifyAll();
        }
    }

    /**
     * @Author : 李道泉
     * @Description :  获取能量总和
     * @Date 2018/4/24 9:04
     * @Modified by :
     */
    public double getTotalEnergies() {

        double sum = 0;
        for (double amount : energyBoxes) {
            sum += amount;
        }
        return sum;
    }

    /**
     * @Author : 李道泉
     * @Description : 返回能量盒子的长度
     * @Date 2018/4/24 9:06
     * @Modified by :
     */
    public int getBoxAmount() {
        return energyBoxes.length;
    }
}
